<template>
  <div class="com-crud">
    <!-- 搜索筛选模块 -->
    <template v-if="searchColumn.length">
      <el-form
        ref="searchRef"
        :model="searchForm"
        :inline="true"
        :size="option.size || 'small'"
        :label-width="option.labelWidth || '80px'"
      >
        <template v-for="item in searchColumn">
          <el-form-item :label="item.label" :key="item.prop">
            <slot :name="item.prop + 'Search'" v-bind:row="item">
              <component
                :is="item.type || 'Input'"
                v-bind="item"
                :value.sync="searchForm[item.prop]"
              ></component>
            </slot>
          </el-form-item>
        </template>
        <template v-if="searchColumn.length">
          <el-form-item style="margin-left: 30px">
            <el-button
              type="primary"
              icon="el-icon-search"
              :loading="searchLoading"
              @click="searchChange"
              >搜索</el-button
            >
            <el-button
              icon="el-icon-delete"
              :disabled="searchLoading"
              @click="searchReset"
              >清空</el-button
            >
          </el-form-item>
        </template>
      </el-form>
    </template>

    <!-- 顶部按钮模块 -->
    <ComMenuTop
      ref="menuTopRef"
      :option="option"
      :selectedRecord="selectedRecord"
      :choiceData="selectionList"
      :allData="data"
      @batch-delete="batchDelete"
      @empty-event="emptyEvent"
      @refresh-list="refreshList"
      @row-save="open('add')"
    >
      <!-- 如果需要传递的slot不固定或者较多，我们可以通过动态插槽名称透传 -->
      <template #[slotName] v-for="(slot, slotName) in $slots">
        <slot :name="slotName" />
      </template>
    </ComMenuTop>

    <!-- 表格模块 -->
    <template>
      <el-table
        ref="table"
        v-bind="option"
        :data="data"
        v-loading="loading"
        :size="option.size || 'small'"
        :max-height="tableHeight"
        @selection-change="selectionChange"
        style="width: 100%"
      >
        <!-- 多选列 -->
        <el-table-column
          type="selection"
          width="50"
          v-if="isShow(option.selection)"
        >
        </el-table-column>
        <!-- 序号列 -->
        <el-table-column
          type="index"
          label="#"
          width="50"
          v-if="isShow(option.index)"
        ></el-table-column>
        <!-- 数据列 -->
        <el-table-column
          v-for="(item, index) in option.column"
          :key="item.prop"
          v-bind="item"
          :show-overflow-tooltip="isShow(item.overHidden)"
        >
          <template slot="header" slot-scope="{ column }">
            <!-- 自定义表头 -->
            <div :style="{ textAlign: option.headerAlign || 'left' }">
              <slot :name="item.prop + 'Header'" :column="column">
                {{ column.label }}
              </slot>
            </div>
          </template>
          <!-- 自定义列 -->
          <template slot-scope="scope">
            <div :style="{ textAlign: option.align || 'left' }">
              <slot :name="item.prop" :row="scope.row">
                <ComTableName :row="scope.row" :column="option.column[index]" />
              </slot>
            </div>
          </template>
        </el-table-column>
        <!-- 操作列 -->
        <el-table-column
          label="操作"
          v-if="isShow(option.operation)"
          fixed="right"
          :width="option.operationWidth || '180px'"
        >
          <template slot-scope="scope">
            <el-button
              v-if="isShow(option.viewBtn)"
              :icon="option.viewBtnIcon || 'el-icon-view'"
              type="text"
              @click="beforeOpen(scope.row, scope.$index, 'view')"
              >{{ option.viewBtnText || "查看" }}</el-button
            >
            <el-button
              v-if="isShow(option.editBtn)"
              :icon="option.editBtnIcon || 'el-icon-edit'"
              type="text"
              @click="beforeOpen(scope.row, scope.$index, 'edit')"
              >{{ option.editBtnText || "编辑" }}</el-button
            >
            <el-button
              v-if="isShow(option.delBtn)"
              :icon="option.delBtnIcon || 'el-icon-delete'"
              type="text"
              @click="rowDel(scope.row, 'del')"
              >{{ option.delBtnText || "删除" }}</el-button
            >
            <!-- 自定义操作栏 -->
            <slot name="menu" :row="scope.row"></slot>
          </template>
        </el-table-column>
      </el-table>
    </template>
    <!-- 分页 -->
    <template v-if="isShow(option.pagination)">
      <ComPagination
        ref="comPagination"
        :page="tablePage"
        @size-change="sizeChange"
        @current-change="currentChange"
      />
    </template>

    <!-- 编辑添加操作模块 -->
    <template>
      <ComDialog
        ref="comDialog"
        :option="dialogOption"
        :visible.sync="dialogOption.visible"
        @on-close="closeDialogHandler"
        @on-submit="onSubmit"
      >
        <!-- 查看 -->
        <template v-if="dialogOption.type === 'view'">
          <ComDescription :list="viewColumn" />
        </template>
        <!-- 编辑 || 添加 -->
        <template v-else>
          <el-form
            :validate-on-rule-change="false"
            :model="addForm"
            :rules="rules"
            :inline="true"
            :size="option.size || 'small'"
            ref="ruleForm"
            :label-width="option.labelWidth || '80px'"
            :style="styleS"
          >
            <el-row>
              <el-col
                v-for="item in formColumn"
                :key="item.label"
                :xs="24"
                :sm="24"
                :lg="item.span ? item.span : 12"
              >
                <el-form-item
                  :label="item.label"
                  :prop="item.prop"
                  class="form-item-box"
                >
                  <slot :name="item.prop + 'Form'" v-bind:row="item">
                    <component
                      :is="item.type || 'Input'"
                      v-bind="item"
                      :value.sync="addForm[item.prop]"
                      style="width: 100%"
                    ></component>
                  </slot>
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>
        </template>
      </ComDialog>

      <!-- 弹窗 -->
      <ComDialog
        ref="comDialog"
        :option="dialogOption"
        :visible.sync="dialogOption.visible"
        @on-close="closeDialogHandler"
        @on-submit="onSubmit"
      >
        <!-- 查看 -->
        <template v-if="dialogOption.type === 'view'">
          <ComDescription :list="viewColumn" />
        </template>
        <!-- 编辑 || 添加 -->
        <template v-else>
          <el-form
            :validate-on-rule-change="false"
            :model="addForm"
            :rules="rules"
            :inline="true"
            :size="option.size || 'small'"
            ref="ruleForm"
            :label-width="option.labelWidth || '80px'"
            :style="styleS"
          >
            <el-row>
              <el-col
                v-for="item in formColumn"
                :key="item.label"
                :xs="24"
                :sm="24"
                :lg="item.span ? item.span : 12"
              >
                <el-form-item
                  :label="item.label"
                  :prop="item.prop"
                  class="form-item-box"
                >
                  <slot :name="item.prop + 'Form'" v-bind:row="item">
                    <component
                      :is="item.type || 'Input'"
                      v-bind="item"
                      :value.sync="addForm[item.prop]"
                      style="width: 100%"
                    ></component>
                  </slot>
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>
        </template>
      </ComDialog>
    </template>
  </div>
</template>

<script>
import ComPagination from "./crud-item/com-pagination.vue";
import ComTableName from "./crud-item/com-table-name.vue";
import ComDescription from "./crud-item/com-descriptions.vue";
import ComMenuTop from "./crud-item/com-menu-top.vue";
import ComDialog from "./crud-item/com-dialog.vue";
import CompFormItem from "./crud-item/formItem";

export default {
  name: "ComCrud",
  components: {
    ComTableName,
    ComDescription,
    ComPagination,
    ComMenuTop,
    ComDialog,
    CompFormItem,
    ...CompFormItem.components,
  },
  props: {
    /**
     * loading:表格加载动画
     * option:配置
     * data:表格数据
     * page:分页
     * query:搜索默认数据
     * form:编辑添加表单数据
     */
    loading: {
      type: Boolean,
      required: true,
      default: () => true,
    },
    option: {
      type: Object,
      required: true,
      default: () => {},
    },
    data: {
      type: Array,
      required: true,
      default: () => [],
    },
    page: {
      type: Object,
      required: true,
      default: () => {},
    },
    query: {
      type: Object,
      default: () => {},
    },
    form: {
      type: Object,
      default: () => {},
    },
  },
  data() {
    return {
      // 表格
      tableHeight: 680, // 表格高度
      tablePage: {
        pageSize: 10,
        currentPage: 1,
        pageSizes: [10, 20, 30, 50],
        total: 0,
      }, // 分页
      selectedRecord: 0, // 批量操作数量
      selectionList: [], // 批量数据

      // 搜索
      searchLoading: false, // 搜索按钮动画
      searchForm: {}, // 搜索
      searchColumn: [], // 需要添加搜索的表格

      // 编辑添加
      addForm: {}, // 添加 || 编辑
      formColumn: [], // 编辑 || 新增 的表格数据
      rowIndex: null, // 编辑操作时下标

      // 查看
      viewColumn: [], // 需要 查看的数据

      // 弹窗配置
      dialogOption: {
        type: "", // 弹窗类型
        visible: false, // 弹窗显示
      },
      smitS: {
        add: "row-save",
        edit: "row-update",
      },
    };
  },
  watch: {
    page: {
      handler: function (newVal) {
        this.tablePage = Object.assign(this.tablePage, newVal);
      },
      immediate: true,
      deep: true,
    },
    // "dialogOption.type": function (type) {
    "dialogOption.visible": function (visible) {
      /* 
        addDisplay: true, // 表单新增时项是否显示 true
        editDisplay: true, // 表单编辑时项是否显示 true
        viewDisplay: true, // 表单查看时项是否显示 true
      */
      if (!visible && this.dialogOption.type === "") return;
      this.formColumn = this.option.column.filter((item) =>
        this.isShow(item[this.dialogOption.type + "Display"])
      );

      switch (this.dialogOption.type) {
        case "view":
          this.viewColumn = this.formColumn.map((item) => {
            item["val"] = this.form[item.prop];
            return item;
          });
          break;
        case "add":
          this.addForm = Object.assign({}, this.setForm(this.formColumn));
          break;
        case "edit":
          console.log(this.form);
          this.addForm = Object.assign({}, this.form);
          break;
      }
    },
  },
  computed: {
    /** 解析表单的正则验证***/
    rules() {
      let rules = this.formColumn.reduce((map, i) => {
        if (i.rules) {
          if (!i.disabled) {
            map[i.prop] = i.rules;
          }
        }
        return map;
      }, {});
      return rules;
    },
    styleS() {
      return {
        "--input-width": this.option.labelWidth || "80px",
      };
    },
    searchVal() {
      console.log(this.searchForm);
      return Object.keys(this.searchForm).reduce((obj, key) => {
        let val = this.searchForm[key];
        if (val != null && val != undefined && val != "") {
          obj[key] = val;
        }
        return obj;
      }, {});
    },
  },
  created() {
    this.setSearchForm();
    this.refreshList();
  },
  mounted() {},
  methods: {
    // 是否显示
    isShow(show) {
      return show === false ? false : true;
    },

    /** 批量操作触发 */
    selectionChange(e) {
      this.selectionList = e;
      this.selectedRecord = e.length;
      this.$emit("selection-change", e);
    },

    // 设置 form 默认值否则可能报错
    setForm(data) {
      return data.reduce((a, b) => {
        if (b.value != undefined) {
          // form 没有对应的值则查看是否设置 value 默认值
          a[b.prop] = b.value;
        } else if (b.type == "Checkbox") {
          // 部分组件需要设置默认值为数组
          a[b.prop] = [];
        } else {
          a[b.prop] = "";
        }
        return a;
      }, {});
    },

    /* 搜索模块 */
    // 设置搜索数据
    setSearchForm() {
      this.searchColumn = this.option.column.filter((item) => {
        if (item.search && item.type != "uploadImg") {
          delete item.value;
          return item;
        }
      });
      this.searchForm = Object.assign(
        this.setForm(this.searchColumn),
        this.query
      );
    },

    // 清空搜索内容
    searchReset() {
      this.setSearchForm();
      this.$emit("search-reset");
    },

    // 搜索内容
    searchChange() {
      this.searchLoading = true;
      this.$emit("search-change", this.searchVal, () => {
        this.searchLoading = false;
      });
    },

    // 顶部按钮模块
    /** 清空批量选中数据 */
    emptyEvent() {
      this.selectedRecord = 0;
      this.$refs["table"].clearSelection();
    },

    /** 批量操作 */
    batchDelete() {
      if (this.selectedRecord == 0 || this.selectedRecord.length == 0) {
        this.$message({
          message: "请至少选择一条数据!!",
          type: "warning",
        });
        return false;
      }
      this.$emit("batch-delete");
    },

    /* 编辑添加模块  */
    // 打开弹窗
    open(type) {
      this.dialogOption.type = type;
      this.dialogOption.visible = true;
    },

    // 关闭弹窗
    closeDialogHandler() {
      // this.$parent.form = {};
      // this.addForm = Object.assign({}, this.setForm(this.formColumn));
      // this.dialogOption.type = "";
    },

    // 弹窗点击提交 done:停止加载动画并关闭弹窗 loading:停止加载动画
    onSubmit(done, loading) {
      this.$refs["ruleForm"].validate((valid) => {
        if (valid) {
          this.$emit(
            this.smitS[this.dialogOption.type],
            this.addForm,
            () => {
              done();
              this.closeDialogHandler();
            },
            () => {
              loading();
            },
            this.rowIndex
          );
        } else {
          loading();
          console.log("error submit!!");
          return false;
        }
      });
    },

    // 编辑或查看操作前需请求到详情数据
    beforeOpen(row, index, type) {
      this.rowIndex = index;
      this.$emit("before-open", row, type, () => {
        this.open(type);
      });
    },

    // 删除
    rowDel(row) {
      this.$emit("row-del", row);
    },

    /** 每页显示条数 */
    sizeChange(pageSize) {
      this.tablePage.pageSize = pageSize;
      this.$emit("size-change", pageSize);
      this.refreshList();
    },

    /** 当前的页数 */
    currentChange(currentPage) {
      this.tablePage.currentPage = currentPage;
      this.$emit("current-change", currentPage);
      this.refreshList();
    },

    /** 刷新表格数据 */
    refreshList() {
      let page = {
        currentPage: this.tablePage.currentPage,
        pageSize: this.tablePage.pageSize,
      };
      console.log("searchVal", this.searchVal);
      this.$emit("on-load", page, this.searchVal);
    },
  },
};
</script>

<style scoped lang="less">
.com-crud {
  width: 100%;
  height: 100%;
}

.form-item-box {
  width: 100%;
  display: flex;
  /deep/.el-form-item__content {
    display: block;
    width: calc(100% - var(--input-width));
  }

  /deep/.el-select,
  /deep/.el-date-editor {
    width: 100% !important;
  }
}
</style>
